/*!
 * \file WtDataWriterAD.h
 * \project WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief WonderTrader高级数据写入器头文件
 * 
 * \details 该文件定义了WtDataWriterAD类，提供高级数据存储系统的数据写入功能，包括：
 *          - LMDB数据库集成：使用Lightning Memory-Mapped Database进行高性能数据存储
 *          - 多周期K线数据写入：支持分钟级(m1/m5)和日线级(d1)数据写入
 *          - Tick数据写入：支持高频Tick数据的快速写入
 *          - 实时缓存管理：通过内存映射文件和循环缓冲区优化写入性能
 *          - 异步任务处理：支持后台异步数据持久化
 *          
 *          与标准WtDataWriter相比，WtDataWriterAD提供：
 *          - 更高的数据写入性能
 *          - 更大的数据容量支持
 *          - 更灵活的缓存策略
 *          - 更好的内存效率
 *          - 异步处理能力
 */

#pragma once
#include "DataDefineAD.h"

#include "../WTSUtils/WtLMDB.hpp"

#include "../Includes/FasterDefs.h"
#include "../Includes/IDataWriter.h"
#include "../Share/StdUtils.hpp"
#include "../Share/BoostMappingFile.hpp"

#include <queue>

typedef std::shared_ptr<BoostMappingFile> BoostMFPtr;	///< Boost内存映射文件智能指针类型定义

NS_WTP_BEGIN
class WTSContractInfo;
NS_WTP_END

USING_NS_WTP;

/*!
 * \class WtDataWriterAD
 * \brief WonderTrader高级数据写入器类
 * 
 * \details 高级数据写入器，基于LMDB数据库和内存映射技术实现高性能数据写入。
 *          该类提供以下核心功能：
 *          
 *          1. 多周期K线数据写入：
 *             - 1分钟K线(m1)
 *             - 5分钟K线(m5)  
 *             - 日线K线(d1)
 *          
 *          2. Tick数据写入：
 *             - 高频Tick数据
 *             - 实时数据更新
 *             - 内存缓存优化
 *          
 *          3. 缓存机制：
 *             - 实时数据缓存
 *             - 内存映射文件
 *             - 自动扩容管理
 *          
 *          4. 异步处理：
 *             - 后台任务队列
 *             - 异步数据持久化
 *             - 线程安全保证
 *          
 *          5. 数据库管理：
 *             - 按交易所分库存储
 *             - LMDB事务管理
 *             - 自动索引维护
 * 
 * \note 该类使用LMDB作为底层存储引擎，适用于高频数据写入场景
 * \warning 需要确保数据库文件的写入权限和存储空间充足
 * \see IDataWriter, WtLMDB, DataDefineAD.h
 */
class WtDataWriterAD : public IDataWriter
{
public:
	WtDataWriterAD();
	~WtDataWriterAD();	

private:
	/*!
	 * \brief 调整实时数据块大小的模板函数
	 * \tparam HeaderType 头部类型
	 * \tparam T 数据项类型
	 * \param mfPtr 内存映射文件指针引用
	 * \param nCount 数据项数量
	 * \return 调整后的数据块指针
	 * 
	 * 根据数据项数量动态调整内存映射文件的大小，确保有足够空间存储数据
	 */
	template<typename HeaderType, typename T>
	void* resizeRTBlock(BoostMFPtr& mfPtr, uint32_t nCount);

public:
	/*!
	 * \brief 初始化数据写入器
	 * \param params 配置参数
	 * \param sink 数据写入回调接口
	 * \return 初始化是否成功
	 * 
	 * 初始化LMDB数据库连接，设置缓存参数，建立数据写入环境
	 */
	virtual bool init(WTSVariant* params, IDataWriterSink* sink) override;
	
	/*!
	 * \brief 释放资源
	 * 
	 * 关闭数据库连接，清理缓存，停止异步任务线程
	 */
	virtual void release() override;

	/*!
	 * \brief 写入Tick数据
	 * \param curTick 当前Tick数据
	 * \param procFlag 处理标志
	 * \return 写入是否成功
	 * 
	 * 将Tick数据写入到LMDB数据库和实时缓存中，同时触发K线数据更新
	 */
	virtual bool writeTick(WTSTickData* curTick, uint32_t procFlag) override;

	/*!
	 * \brief 获取当前Tick数据
	 * \param code 合约代码
	 * \param exchg 交易所代码（可选）
	 * \return 当前Tick数据指针
	 * 
	 * 从实时缓存中获取指定合约的最新Tick数据
	 */
	virtual WTSTickData* getCurTick(const char* code, const char* exchg = "") override;

private:
	IBaseDataMgr*		_bd_mgr;			///< 基础数据管理器指针

	/*!
	 * \brief Tick数据缓存相关成员变量
	 */
	StdUniqueMutex	_mtx_tick_cache;		///< Tick缓存线程安全互斥锁
	std::string		_cache_file_tick;		///< Tick缓存文件路径
	faster_hashmap<std::string, uint32_t> _tick_cache_idx;	///< Tick缓存索引映射表
	BoostMFPtr		_tick_cache_file;		///< Tick缓存内存映射文件指针
	RTTickCache*	_tick_cache_block;		///< Tick实时缓存块指针

	/*!
	 * \struct _RTBarCacheWrapper
	 * \brief 实时K线缓存包装器结构体
	 * 
	 * \details 用于管理实时K线数据的内存缓存，包含：
	 *          - 线程安全的互斥锁
	 *          - 内存映射文件管理
	 *          - 数据索引映射
	 *          - 缓存块指针
	 */
	typedef struct _RTBarCacheWrapper
	{
		StdUniqueMutex	_mtx;			///< 线程安全互斥锁
		std::string		_filename;		///< 缓存文件名
		faster_hashmap<std::string, uint32_t> _idx;	///< 数据索引映射表
		BoostMFPtr		_file_ptr;		///< 内存映射文件指针
		RTBarCache*		_cache_block;	///< 实时K线缓存块指针

		_RTBarCacheWrapper():_cache_block(NULL),_file_ptr(NULL){}

		/*!
		 * \brief 检查缓存是否为空
		 * \return true表示缓存为空，false表示缓存有数据
		 */
		inline bool empty() const { return _cache_block == NULL; }
	} RTBarCacheWrapper;

	RTBarCacheWrapper _m1_cache;		///< 1分钟K线缓存
	RTBarCacheWrapper _m5_cache;		///< 5分钟K线缓存
	RTBarCacheWrapper _d1_cache;		///< 日线K线缓存

	/*!
	 * \brief 异步任务处理相关成员变量
	 */
	typedef std::function<void()> TaskInfo;		///< 任务信息类型定义
	std::queue<TaskInfo>	_tasks;				///< 任务队列
	StdThreadPtr			_task_thrd;			///< 任务处理线程指针
	StdUniqueMutex			_task_mtx;			///< 任务队列互斥锁
	StdCondVariable			_task_cond;			///< 任务条件变量
	bool					_async_task;		///< 是否启用异步任务处理

	/*!
	 * \brief 配置和状态相关成员变量
	 */
	std::string		_base_dir;			///< 数据存储根目录
	uint32_t		_log_group_size;	///< 日志组大小
	bool			_terminated;		///< 是否已终止标志

	/*!
	 * \brief 数据写入开关配置
	 */
	bool			_disable_tick;		///< 是否禁用Tick数据写入
	bool			_disable_min1;		///< 是否禁用1分钟K线写入
	bool			_disable_min5;		///< 是否禁用5分钟K线写入
	bool			_disable_day;		///< 是否禁用日线写入

private:
	//////////////////////////////////////////////////////////////////////////
	/*!
	 * \brief LMDB数据库定义说明
	 * 
	 * \details 数据库组织结构：
	 *          
	 *          K线数据：按交易所和周期分库存储
	 *          - m1数据库：./m1/CFFEX（每个交易所一个数据库）
	 *          - m5数据库：./m5/CFFEX
	 *          - d1数据库：./d1/CFFEX
	 *          
	 *          Tick数据：按合约分库存储
	 *          - Tick数据库：./ticks/CFFEX/IF2101（每个合约一个数据库）
	 *          
	 *          这种设计提供了：
	 *          - 高效的数据分区
	 *          - 灵活的数据管理
	 *          - 优化的写入性能
	 *          - 良好的扩展性
	 */
	typedef std::shared_ptr<WtLMDB> WtLMDBPtr;						///< LMDB数据库智能指针类型定义
	typedef faster_hashmap<std::string, WtLMDBPtr> WtLMDBMap;		///< LMDB数据库映射表类型定义

	WtLMDBMap	_exchg_m1_dbs;		///< 按交易所分类的1分钟K线数据库映射
	WtLMDBMap	_exchg_m5_dbs;		///< 按交易所分类的5分钟K线数据库映射
	WtLMDBMap	_exchg_d1_dbs;		///< 按交易所分类的日线K线数据库映射

	WtLMDBMap	_tick_dbs;			///< 按"交易所.合约"为键的Tick数据库映射（如BINANCE.BTCUSDT）

	/*!
	 * \brief 获取K线数据库指针
	 * \param exchg 交易所代码
	 * \param period K线周期
	 * \return LMDB数据库智能指针
	 * 
	 * 根据交易所和K线周期获取对应的LMDB数据库连接
	 */
	WtLMDBPtr	get_k_db(const char* exchg, WTSKlinePeriod period);

	/*!
	 * \brief 获取Tick数据库指针
	 * \param exchg 交易所代码
	 * \param code 合约代码
	 * \return LMDB数据库智能指针
	 * 
	 * 根据交易所和合约代码获取对应的Tick数据库连接
	 */
	WtLMDBPtr	get_t_db(const char* exchg, const char* code);

private:
	/*!
	 * \brief 加载缓存数据
	 * 
	 * 从磁盘文件加载已有的缓存数据到内存中
	 */
	void loadCache();

	/*!
	 * \brief 更新Tick缓存
	 * \param ct 合约信息指针
	 * \param curTick 当前Tick数据
	 * \param procFlag 处理标志
	 * \return 更新是否成功
	 * 
	 * 将新的Tick数据更新到实时缓存中
	 */
	bool updateTickCache(WTSContractInfo* ct, WTSTickData* curTick, uint32_t procFlag);

	/*!
	 * \brief 更新K线缓存
	 * \param ct 合约信息指针
	 * \param curTick 当前Tick数据
	 * 
	 * 根据Tick数据更新相应的K线缓存
	 */
	void updateBarCache(WTSContractInfo* ct, WTSTickData* curTick);

	/*!
	 * \brief 将Tick数据写入数据库
	 * \param ct 合约信息指针
	 * \param curTick 当前Tick数据
	 * 
	 * 将Tick数据持久化到LMDB数据库
	 */
	void pipeToTicks(WTSContractInfo* ct, WTSTickData* curTick);

	/*!
	 * \brief 将日K线数据写入数据库
	 * \param ct 合约信息指针
	 * \param bar K线数据结构
	 * 
	 * 将日K线数据持久化到LMDB数据库
	 */
	void pipeToDayBars(WTSContractInfo* ct, const WTSBarStruct& bar);

	/*!
	 * \brief 将1分钟K线数据写入数据库
	 * \param ct 合约信息指针
	 * \param bar K线数据结构
	 * 
	 * 将1分钟K线数据持久化到LMDB数据库
	 */
	void pipeToM1Bars(WTSContractInfo* ct, const WTSBarStruct& bar);

	/*!
	 * \brief 将5分钟K线数据写入数据库
	 * \param ct 合约信息指针
	 * \param bar K线数据结构
	 * 
	 * 将5分钟K线数据持久化到LMDB数据库
	 */
	void pipeToM5Bars(WTSContractInfo* ct, const WTSBarStruct& bar);

	/*!
	 * \brief 推送任务到异步队列
	 * \param task 任务信息
	 * 
	 * 将数据持久化任务添加到异步处理队列中
	 */
	void pushTask(TaskInfo task);
};

